package com.xmut.mall.order.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.xmut.mall.order.constant.PayConstant;
import com.xmut.mall.order.entity.OrderEntity;
import com.xmut.mall.order.entity.OrderLogEntity;
import com.xmut.mall.order.entity.TradeEntity;
import com.xmut.mall.order.feign.WareFeignService;
import com.xmut.mall.order.myenum.OrderStatusEnum;
import com.xmut.mall.order.myenum.PayStatusEnum;
import com.xmut.mall.order.myenum.PaymentMethodEnum;
import com.xmut.mall.order.myenum.UserEnums;
import com.xmut.mall.order.myexpection.WareReduceFailException;
import com.xmut.mall.order.service.OrderLogService;
import com.xmut.mall.order.service.OrderService;
import com.xmut.mall.order.service.TradeService;
import com.xmut.mall.order.utils.RespBean;
import com.xmut.mall.order.vo.HandlerPayVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.xmut.mall.order.dao.PaymentLogDao;
import com.xmut.mall.order.entity.PaymentLogEntity;
import com.xmut.mall.order.service.PaymentLogService;
import org.springframework.transaction.annotation.Transactional;


@Service("paymentLogService")
public class PaymentLogServiceImpl extends ServiceImpl<PaymentLogDao, PaymentLogEntity> implements PaymentLogService {

    @Autowired
    private OrderService orderService;

    @Autowired
    private TradeService tradeService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private OrderLogService orderLogService;

    @Autowired
    private WareFeignService wareFeignService;

    /**
     * 处理支付请求
     *
     * @param vo
     * @return
     */
    @Override
    public RespBean handlePay(HandlerPayVo vo) {
        // 根据交易号码获取订单
        List<OrderEntity> orderList = orderService.list(new QueryWrapper<OrderEntity>()
                .eq("trade_sn", vo.getSn()));
        // 判断当前订单状态
        for (OrderEntity orderEntity : orderList) {
            if (orderEntity.getOrderStatus().equals(OrderStatusEnum.CANCELLED)) {
                return RespBean.error("当前订单已取消");
            }
            if (orderEntity.getOrderStatus().equals(OrderStatusEnum.TAKE)) {
                return RespBean.error("当前订单带核验");
            }
            if (!orderEntity.getClientType().equals(vo.getClientType())) {
                return RespBean.error("交易客户端错误");
            }
        }
        // 获取当前交易详情
        TradeEntity trade = tradeService.getOne(new QueryWrapper<TradeEntity>().eq("sn", vo.getSn()));
        if (!trade.getPayStatus().equals(PayStatusEnum.UNPAID.description())) {
            return RespBean.error("当前交易已取消");
        }

        // 组装支付地址
        StringBuffer qrCode = new StringBuffer();
        String uuid = IdUtil.fastSimpleUUID();
        // 设置uuid防止二维码重复使用重复支付 设置1分钟有效
        redisTemplate.opsForValue().set(uuid, vo.getSn(), 15, TimeUnit.MINUTES);
        qrCode.append(PayConstant.PUBLIC_NET_ADDRESS + "/api/order/paymentlog/pay");
        qrCode.append("?clientType=" + vo.getClientType());
        qrCode.append("&orderType=" + vo.getOrderType());
        qrCode.append("&paymentClient=" + vo.getPaymentClient());
        qrCode.append("&paymentMethod=" + vo.getPaymentMethod());
        qrCode.append("&price=" + vo.getPrice());
        qrCode.append("&sn=" + vo.getSn());
        qrCode.append("&code=" + uuid);
        qrCode.append("&userId=" + vo.getUserId());


        return RespBean.success("二维码生成", qrCode.toString());
    }

    /**
     * 进行支付
     *
     * @param vo
     * @param code
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public RespBean pay(HandlerPayVo vo, String code) {

        String uuid = redisTemplate.opsForValue().get(code);
        if (StrUtil.isEmpty(uuid)) {
            // 新增交易log
            initPaymentLog(vo, "二维码过期");

            return RespBean.error("二维码过期");
        } else {
            redisTemplate.delete(code);
            // 进行对账
            // 查询当前交易单号
            TradeEntity tradeEntity = tradeService.getOne(new QueryWrapper<TradeEntity>().eq("sn", vo.getSn()));
            if (ObjectUtil.isEmpty(tradeEntity)) {
                initPaymentLog(vo, "交易不存在");
                // 如果没查到就是错误的交易号码
                return RespBean.error("交易不存在");
            }
            if (!tradeEntity.getPayStatus().equals(PayStatusEnum.UNPAID.description())) {
                initPaymentLog(vo, "当前交易已结束");
                // 对比交易状态
                return RespBean.error("当前交易已结束");
            }
            if (vo.getPrice().compareTo(tradeEntity.getFlowPrice()) != 0) {
                initPaymentLog(vo, "交易金额错误");
                // 对账 如果结算金额对不上就返回错误
                return RespBean.error("交易金额错误");
            }

            // 修改交易结果
            boolean update = tradeService.update(new UpdateWrapper<TradeEntity>()
                    .set("pay_status", PayStatusEnum.PAID.description())
                    .set("payment_method", vo.getPaymentMethod())
                    .eq("sn", vo.getSn()));

            // 修改订单的状态
            orderService.update(new UpdateWrapper<OrderEntity>()
                    .set("order_status", OrderStatusEnum.PAID.description())
                    .set("pay_status", PayStatusEnum.PAID.description())
                    .set("payment_method", vo.getPaymentMethod())
                    .set("payment_time", new Date())
                    .eq("trade_sn", vo.getSn()));

            // 生成订单日志 解锁库存
            List<OrderEntity> orderList = orderService.list(new QueryWrapper<OrderEntity>().eq("trade_sn", vo.getSn()));
            for (OrderEntity orderEntity : orderList) {
                OrderLogEntity orderLogEntity = new OrderLogEntity();
                orderLogEntity.setCreateTime(new Date());
                orderLogEntity.setMessage("订单[" + orderEntity.getSn() + "]支付");
                orderLogEntity.setOperatorId(orderEntity.getMemberId());
                orderLogEntity.setOperatorName(orderEntity.getMemberName());
                orderLogEntity.setOperatorType(UserEnums.MEMBER.name());
                orderLogEntity.setOrderSn(orderEntity.getSn());
                orderLogService.save(orderLogEntity);

//                // 解锁库存
//                Map<String,Object> param = new HashMap<>();
//                param.put("orderSN",orderEntity.getSn());
//                RespBean respBean = wareFeignService.unLockStockWhenOrderPayed(param);
//                if (respBean.getCode()==500){
//                    initPaymentLog(vo,"库存扣减失败");
//                    throw new WareReduceFailException("库存扣减调用失败");
//                }
            }




            if (update) {
                initPaymentLog(vo, "支付成功");
                return RespBean.success("支付成功");
            } else {
                initPaymentLog(vo, "支付失败");
                return RespBean.error("支付失败");
            }
        }

    }

    /**
     * 前端定时器5秒一次轮训该接口 查询当前交易的状态
     *
     * @param vo
     * @return
     */
    @Override
    public RespBean payCallBack(HandlerPayVo vo) {
        // 根据sn查询当前交易单
        TradeEntity trade = tradeService.getOne(new QueryWrapper<TradeEntity>().eq("sn", vo.getSn()));
        if (trade.getPayStatus().equals(PayStatusEnum.PAID.description())) {
            // 当轮训发现支付完成之后 修改订单状态为未发货
            orderService.update(new UpdateWrapper<OrderEntity>()
                    .set("order_status",OrderStatusEnum.UNDELIVERED.description())
                    .eq("trade_sn",vo.getSn()));
            return RespBean.success("支付成功");
        } else {
            return RespBean.error("未支付");
        }

    }

    public void initPaymentLog(HandlerPayVo vo, String info) {
        PaymentLogEntity paymentLog = new PaymentLogEntity();
        paymentLog.setTradeSn(vo.getSn());
        paymentLog.setClientType(vo.getClientType());
        paymentLog.setFlowPrice(vo.getPrice());
        paymentLog.setMemberId(vo.getUserId());
        paymentLog.setOrderType(vo.getOrderType());
        // 根据交易号查询订单
        List<OrderEntity> orderList = orderService.list(new QueryWrapper<OrderEntity>()
                .eq("trade_sn", vo.getSn()));
        String payOrderNo = new String();
        for (OrderEntity orderEntity : orderList) {
            payOrderNo = payOrderNo + orderEntity.getSn() + ",";
        }
        paymentLog.setPayOrderNo(payOrderNo);
        paymentLog.setPayStatus(PayStatusEnum.PAID.description());
        paymentLog.setPaymentMethod(vo.getPaymentMethod());
        paymentLog.setPaymentTime(new Date());
        paymentLog.setSn(vo.getSn());
        paymentLog.setStoreId(orderList.get(0).getStoreId());
        paymentLog.setStoreName(orderList.get(0).getStoreName());
        paymentLog.setCreateTime(new Date());
        paymentLog.setPaymentInfo(info);
        this.save(paymentLog);
    }

}